// 顶部：仅类型导入 + 拆分 logger 的值/类型导入
import Logger from "../../logger";
import type { ILogger } from "../../logger";
import { LoggerLevel } from "../../logger";
import utilsReplace from "../replace";
import type { IDateCountDownParams, IDateJsonResult, IDateParams, IDateToJsonParams, IUtilsDate } from "./date";

export type {
    IDateCountDownParams, IDateJsonResult, IDateParams, IDateToJsonParams,
}

class UtilsDate implements IUtilsDate {
    private readonly logger: ILogger;

    private _replaceFormatDate(str: string): string {
        if (str.indexOf('yyyy') >= 0) str = str.replace('yyyy', '{yyyy}');
        else if (str.indexOf('yy') >= 0) str = str.replace('yy', '{yy}');
        if (str.indexOf('MM') >= 0) str = str.replace('MM', '{MM}');
        if (str.indexOf('dd') >= 0) str = str.replace('dd', '{dd}');
        if (str.indexOf('HH') >= 0) str = str.replace('HH', '{HH}');
        if (str.indexOf('hh') >= 0) str = str.replace('hh', '{hh}');
        if (str.indexOf('mm') >= 0) str = str.replace('mm', '{mm}');
        if (str.indexOf('ss') >= 0) str = str.replace('ss', '{ss}');
        return str
    }

    private _checkDate(date: string | number): number {
        if (typeof date === 'number') return date;
        if (!date.length) return 0;
        if (date.indexOf('0001/01/01') === 0) return 0;
        if (date.indexOf('-') >= 0) date = date.replace(/-/g, '/');
        return new Date(date).getTime();
    }

    constructor(loggerLevel?: LoggerLevel) {
        this.logger = new Logger('utils_date', loggerLevel);
    }

    format(data: string | number, params?: IDateParams): string {
        params = params || {};
        const format = typeof params.format === 'string' ? params.format : 'yyyy-MM-dd hh:mm:ss';
        return utilsReplace.strByJson(this._replaceFormatDate(format), this.formatToJson(data, params));
    }

    formatUTC(data: string | number, params?: IDateParams): string {
        params = params || {};
        const format = typeof params.format === 'string' ? params.format : 'yyyy-MM-dd hh:mm:ss';
        const _value = this._checkDate(data);
        if (!_value) return '';
        const _timezoneOffset = new Date().getTimezoneOffset() * 60 * 1000;
        let _time = new Date(_value).getTime();
        _time = new Date(_time - _timezoneOffset).getTime();
        return utilsReplace.strByJson(this._replaceFormatDate(format), this.formatToJson(_time, params));
    }

    formatToUTC(data: string | number, params?: IDateParams): string {
        params = params || {};
        const format = typeof params.format === 'string' ? params.format : 'yyyy-MM-dd hh:mm:ss';
        const _value = this._checkDate(data);
        if (!_value) return '';
        const _timezoneOffset = new Date().getTimezoneOffset() * 60 * 1000;
        let _time = new Date(_value).getTime();
        _time = new Date(_time + _timezoneOffset).getTime();
        return utilsReplace.strByJson(this._replaceFormatDate(format), this.formatToJson(_time, params));
    }

    formatToJson(data: string | number, params?: IDateToJsonParams): IDateJsonResult {
        params = params || {};
        const _value = this._checkDate(data);
        const result: IDateJsonResult = {
            yyyy: '', yy: '', MM: '', dd: '', HH: '', hh: '', mm: '', ss: '', day: 0, time: 0
        }
        if (!_value) return result;
        const varDate = new Date(_value);
        if (params.day) {
            if (typeof params.day && !isNaN(params.day)) varDate.setDate(varDate.getDate() + params.day);
        }
        result.yyyy = varDate.getFullYear().toString();
        result.yy = result.yyyy.substring(2, result.yyyy.length);
        result.MM = (varDate.getMonth() + 1).toString();
        result.dd = varDate.getDate().toString();
        result.HH = varDate.getHours().toString();
        result.hh = varDate.getHours().toString();
        result.mm = varDate.getMinutes().toString();
        result.ss = varDate.getSeconds().toString();
        result.day = varDate.getDay();
        result.time = varDate.getTime();
        result.MM = result.MM.length > 1 ? result.MM : `0${result.MM}`;
        result.dd = result.dd.length > 1 ? result.dd : `0${result.dd}`;
        result.HH = result.HH.length > 1 ? result.HH : `0${result.HH}`;
        result.hh = result.hh.length > 1 ? result.hh : `0${result.hh}`;
        result.mm = result.mm.length > 1 ? result.mm : `0${result.mm}`;
        result.ss = result.ss.length > 1 ? result.ss : `0${result.ss}`;
        return result;
    }

    countDown(endDate: number, params?: IDateCountDownParams): void {
        params = params || {};
        const format = params.format ?? 'dd hh:mm:ss';
        const _endDate = this._checkDate(endDate);
        if (!_endDate) {
            this.logger.warn('dateCountDown()', `endDate不是时间`)
            return
        }
        const dateJson = this.formatToJson(_endDate);
        let prev = '';//上一条数据
        const end = dateJson.time ?? 0;
        if (typeof params.startCallback === "function") params.startCallback();
        const intTime = setInterval(() => {
            const curr = new Date().getTime();
            const time = end - curr;
            let dd = Math.floor(time / (1000 * 60 * 60 * 24));
            if (dd <= 0) dd = 0;
            let hh = Math.floor(time / (1000 * 60 * 60) % 24);
            if (hh <= 0) hh = 0;
            let mm = Math.floor(time / (1000 * 60) % 60);
            if (mm <= 0) mm = 0;
            let ss = Math.floor(time / 1000 % 60);
            if (ss <= 0) ss = 0;
            const resultTimeString = utilsReplace.strByJson(format, { dd, HH: hh, hh, mm, ss });

            //  输出
            if (prev !== resultTimeString) {
                prev = resultTimeString;
                if (params && typeof params.callback === "function") params.callback(resultTimeString);
            }

            //  结束
            if (dd === 0 && hh === 0 && mm === 0 && ss === 0) {
                clearInterval(intTime);
                if (params && typeof params.endCallback === "function") params.endCallback();
            }
        }, 100);
    }
}

export default new UtilsDate() as IUtilsDate;
